package com.jintian.smart.kernel.common.expr.datameta;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import com.jintian.smart.kernel.common.expr.format.FormatException;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 基础数据描述对象 完成
 */
public abstract class BaseDataMeta {

	// 数据类型
	public enum DataType {

		// 字符窜
		DATATYPE_STRING,
		// 布尔类
		DATATYPE_BOOLEAN,
		// 整数
		DATATYPE_INT,
		// 长整数
		DATATYPE_LONG,
		// 浮点数
		DATATYPE_FLOAT,
		// 双精度浮点
		DATATYPE_DOUBLE,
		//
		DATATYPE_BIGDECIMAL,
		// 日期时间
		DATATYPE_DATE,
		// 集合对象
		DATATYPE_LIST,
		// MAP对象
		DATATYPE_MAP,
		// 通用对象类型
		DATATYPE_OBJECT;

	}

	// 数据类型
	DataType dataType;
	// 值
	Object dataValue;
	// // 引用类型标识
	// private boolean isReference;

	public BaseDataMeta(DataType dataType, Object dataValue) {
		this.dataType = dataType;
		this.dataValue = dataValue;
		// 参数类型校验
		verifyDataMeta();

	}

	public DataType getDataType() {
		if (isReference()) {
			return this.getReference().getDataType();
		} else {
			return dataType;
		}
	}

	public Object getDataValue() {
		return dataValue;
	}

	public void setDataValue(Object value) {
		this.dataValue = value;
	}

	/**
	 * 
	 */
	public String getDataValueText() {

		if (dataValue == null) {
			return null;

		} else if (DataType.DATATYPE_DATE == this.dataType) {
			return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) dataValue);

		} else if (DataType.DATATYPE_LIST == this.dataType) {
			StringBuffer buff = new StringBuffer("[");
			@SuppressWarnings("rawtypes")
			List col = (List) dataValue;
			for (Object o : col) {
				if (o == null) {
					buff.append("null, ");
				} else if (o instanceof Date) {
					buff.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) o)).append(", ");
				} else {
					buff.append(o.toString()).append(", ");
				}
			}
			buff.append("]");
			if (buff.length() > 2) {
				buff.delete(buff.length() - 3, buff.length() - 1);
			}
			return buff.toString();

		} else {
			return dataValue.toString();
		}
	}

	/**
	 * 获取Token的字符窜类型值
	 * 
	 * @return
	 */
	public String getStringValue() {
		return TypeUtils.castToString(this.dataValue);
	}

	/**
	 * 获取Token的boolean类型值
	 * 
	 * @return
	 */
	public Boolean getBooleanValue() {
		return TypeUtils.castToBoolean(this.dataValue);
	}

	/**
	 * 获取Token的int类型值
	 * 
	 * @return
	 */
	public Integer getIntegerValue() {
		return TypeUtils.castToInt(this.dataValue);
	}

	/**
	 * 获取Token的long类型值
	 * 
	 * @return
	 */
	public Long getLongValue() {
		return TypeUtils.castToLong(this.dataValue);
	}

	/**
	 * 获取Token的float类型值
	 * 
	 * @return
	 */
	public Float getFloatValue() {
		return TypeUtils.castToFloat(this.dataValue);
	}

	/**
	 * 获取Token的double类型值
	 * 
	 * @return
	 */
	public Double getDoubleValue() {
		return TypeUtils.castToDouble(this.dataValue);
	}

	public BigDecimal getBigDecimalValue() {
		return TypeUtils.castToBigDecimal(this.dataValue);
	}

	/**
	 * 获取Token的Date类型值
	 * 
	 * @return
	 */
	public Date getDateValue() {
		return TypeUtils.castToDate(this.dataValue);
	}

	/**
	 * 获取数据的集合对象
	 * 
	 * @return
	 */

	@SuppressWarnings("unchecked")
	public List<Object> getCollection() {
		return TypeUtils.cast(this.dataValue, ArrayList.class, ParserConfig.getGlobalInstance());
	}

	@SuppressWarnings("rawtypes")
	public Map getMap() {
		return TypeUtils.cast(this.dataValue, HashMap.class, ParserConfig.getGlobalInstance());
	}

	/**
	 * 获取Token的引用对象
	 * 
	 * @return
	 */
	public Reference getReference() {
		return (Reference) dataValue;
	}

	@Override
	public boolean equals(Object o) {
		if (o == this) {
			return true;

		} else if (o instanceof BaseDataMeta) {

			BaseDataMeta bdo = (BaseDataMeta) o;
			if (this.isReference() && bdo.isReference()) {
				return this.getReference() == bdo.getReference();
			}

			if (bdo.dataType == dataType) {
				if (bdo.dataValue != null && bdo.dataValue.equals(dataValue)) {
					return true;
				} else if (bdo.dataValue == null && dataValue == null) {
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}

		} else {
			return false;
		}
	}

	/**
	 * 校验数据类型和值得合法性
	 */
	protected void verifyDataMeta() {
		if (dataType != null && dataValue != null) {
			if (DataType.DATATYPE_BOOLEAN == dataType) {
				try {
					getBooleanValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_DATE == dataType) {
				try {
					getDateValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_DOUBLE == dataType) {
				try {
					getDoubleValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_BIGDECIMAL == dataType) {
				try {
					getBigDecimalValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_FLOAT == dataType) {
				try {
					getFloatValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_INT == dataType) {
				try {
					getIntegerValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_LONG == dataType) {
				try {
					getLongValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_STRING == dataType) {
				try {
					getStringValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_LIST == dataType) {
				try {
					getCollection();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (this.isReference()) {
				try {
					getReference();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			} else if (DataType.DATATYPE_OBJECT == dataType) {
				try {
					getDataValue();
				} catch (UnsupportedOperationException e) {
					throw new IllegalArgumentException("数据类型不匹配; 类型：" + dataType + ",值:" + dataValue);
				}

			}
		}
	}

	public Class<?> mapTypeToJavaClass() {

		if (DataType.DATATYPE_BOOLEAN == this.getDataType()) {
			return Boolean.class;

		} else if (DataType.DATATYPE_DATE == this.getDataType()) {
			return Date.class;

		} else if (DataType.DATATYPE_DOUBLE == this.getDataType()) {
			return Double.class;

		} else if (DataType.DATATYPE_BIGDECIMAL == this.getDataType()) {
			return BigDecimal.class;

		} else if (DataType.DATATYPE_FLOAT == this.getDataType()) {
			return Float.class;

		} else if (DataType.DATATYPE_INT == this.getDataType()) {
			return Integer.class;

		} else if (DataType.DATATYPE_LONG == this.getDataType()) {
			return Long.class;

		} else if (DataType.DATATYPE_STRING == this.getDataType()) {
			return String.class;

		} else if (DataType.DATATYPE_LIST == this.getDataType()) {
			return List.class;

		} else if (DataType.DATATYPE_MAP == this.getDataType()) {
			return Map.class;
		} else if (DataType.DATATYPE_OBJECT == this.getDataType()) {
			return Object.class;
		}
		throw new FormatException("映射Java类型失败：无法识别的数据类型");
	}

	/**
	 * 
	 */
	public Object toJavaObject() {
		if (null == this.dataValue) {
			return null;
		}
		if (this.isReference()) {
			Constant c = this.getReference().execute();
			while (c.isReference()) {
				Reference ref = (Reference) c.getDataValue();
				c = ref.execute();
			}
			return c.toJavaObject();
		}

		if (DataType.DATATYPE_BOOLEAN == this.getDataType()) {
			return getBooleanValue();

		} else if (DataType.DATATYPE_DATE == this.getDataType()) {
			return getDateValue();

		} else if (DataType.DATATYPE_DOUBLE == this.getDataType()) {
			return getDoubleValue();

		} else if (DataType.DATATYPE_BIGDECIMAL == this.getDataType()) {
			return getBigDecimalValue();

		} else if (DataType.DATATYPE_FLOAT == this.getDataType()) {
			return getFloatValue();

		} else if (DataType.DATATYPE_INT == this.getDataType()) {
			return getIntegerValue();

		} else if (DataType.DATATYPE_LONG == this.getDataType()) {
			return getLongValue();

		} else if (DataType.DATATYPE_STRING == this.getDataType()) {
			return getStringValue();

		} else if (DataType.DATATYPE_LIST == this.getDataType()) {
			return getCollection();
		} else if (DataType.DATATYPE_MAP == this.getDataType()) {
			return getMap();
		} else {
			return getDataValue();
		}
	}

	public Object cast(Class<?> clazz) {
		if (null == this.dataValue) {
			return null;
		}
		if (this.dataValue instanceof Constant) {
			Constant c = (Constant) this.dataValue;
			while (c.isReference()) {
				Reference ref = (Reference) c.getDataValue();
				c = ref.execute();
			}
			return c.cast(clazz);
		}
		return TypeUtils.cast(this.dataValue, clazz, ParserConfig.getGlobalInstance());
	}

	public boolean isReference() {
		return this.dataValue instanceof Reference;
	}
	//
	// void setReference(boolean isReference) {
	// this.isReference = isReference;
	// }

}
